<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta http-equiv="X-UA-Compatible" content="IE=edge">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Document</title>
</head>
<body>
  <script>
    // 查找保存在独特空间中的资源
    function find(arr,item){
      for(var i=0; i<arr.length; i++){
        if(arr[i].source === item){
          return arr[i]
        }
      }
      return null;
    }

    function deepClone(data, uniqueList = []){
      // 判断数据类型
      const type = judgeType(data);
      // 声明变量保存value
      let obj;
      // 判断obj为哪种类型
      if(type === 'array'){
        obj = [];
      } else if(type === 'object'){
        obj = {};
      } else {
        // 既不是数组也不是对象，则为基本数据类型，直接返回
        return data;
      }

      let uniqueData = find(uniqueList, data);
      if(uniqueData) return uniqueData.target;

      if(type === 'array'){
        for(let i = 0; i < data.length; i++){
          obj.push(this.deepClone(data[i]), uniqueList);
        }
      } else {
        for (let key in data){
          obj[key] = this.deepClone(data[key], uniqueList);
        }
      }

      uniqueList.push({
        source:data,
        target:obj
      });

      return obj;
    }

    function judgeType(obj){
      // 判断obj的数据类型
      const toString = Object.prototype.toString.call(obj);
      const map = {
        '[object Boolean]': 'boolean',
        '[object Number]': 'number',
        '[object String]': 'string',
        '[object Function]': 'function',
        '[object Array]': 'array',
        '[object Date]': 'date',
        '[object RegExp]': 'regExp',
        '[object Undefined]': 'undefined',
        '[object Null]': 'null',
        '[object Object]': 'object'
      }

      if(obj instanceof Element){
        return 'element';
      }

      return map[toString];
    }

  </script>
</body>
</html>